#|______________________________________________________________________________
 |
 | plots003.lsp
 |
 | Contains the following constructor functions for the new ViSta Plots System
 | Unlike the rest of the new system, these are redefined functions
 |
 |   mosaic-plot         interface to mosaic-pot-classic and mosaic-plot-new
 |   mosaic-plot-classic renamed original mosaic-plot function
 |   mosaic-plot-new     new function for plots menu
 |
 |   bar-graph           interface to bar-graph-classic and bar-graph-new
 |   bar-graph-classic   renamed original bar-graph function 
 |   bar-graph-new       new function for plots menu
 |
 |______________________________________________________________________________
 |#

(defun mosaic-plot (&optional (data nil data?) &rest args)
"Creates a mosaic plot of 1- to 4-way data.

MOSAIC-PLOT accepts two types of data: CELL DATA (data organized as table cells) and VARIABLE DATA (data organized as variables). The type of data is determined from the nature of the arguments: If there are at least two arguments, and the first two are each a list, the data are CELL data. Otherwise, they are VARIABLE DATA.

Arguments for CELL data:
REQUIRED:     CELLS   list of cells in way-major order. 
              LEVELS  list giving the number of levels for each way. 
KEYWORDS:     (see below)

Arguments for VARIABLE data:
OPTIONAL:     DATA    identifies the data (see below).
KEYWORDS:     (see below)

DATA - The optional DATA argument may be omitted or NIL, or may be a data object, a list of numeric or string elements, a list of variable objects, a list of single-quoted symbolic variable names, a list of equal-length lists, a vector, a list of equal-length vectors, or a matrix. If not specified or NIL, DATA is assumed to be $, the current dataobject. In all cases DATA is converted into a list of equal-length vectors, one vector for each CATEGORY variable in $, the current-data. The plot is constructed from the first vector in the list of vectors.

Keyword arguments for both types of data:
KEYWORD:     WAY-LABELS, LEVEL-LABELS, FREQ, STACKED, 
             COLOR-VALUES, (STANDARDIZE T), (CONNECT T) 
             IN, (SHOW T), LOCATION, SIZE, TITLE, MENU,  
             LEGEND1, LEGEND2, TOP-MOST, GO-AWAY, CONTENT-ONLY

Keyword arguments which are unique to MOSAIC-PLOT:
WAY-LABELS   A list specifying the names of the ways.
LEVEL-LABELS A list of lists, one sublist for each way of the data.
             The lists are in the same order as the way-labels.
             Each sublist specifies the names of the levels of a way.
FREQ         Indicates whether the data are frequency data. 
STACKED      Indicates whether intial plot is stacked (when possible)
             or side-by-side bar graph.
COLOR-VALUES A list, in way-major order, used to color cells according 
             to the specified values (standardized when STANDARDIZE T).
             By default, ViSta generates the color values.
STANDARDIZE  T or NIL determines if the color-values are standardized.
CONNECT      Indicates whether bars are connected by rows.

Keyword arguments shared with other plots:
IN (unused)  T, NIL, (UNUSED) or CONTAINER (see below)
SHOW (T)     T or NIL determines if the plot is shown when created
TOP-MOST (T) T or NIL determines whether plots are always on top
LOCATION     a list (x y) locating the plot's upper-left corner 
SIZE         a list (w h) of the plot's width & height 
MENU         T or NIL to install the graph's menu on the menubar
TITLE        a  string shown in the graph window title bar 
LEGEND1      a string for the first line of the legend 
LEGEND2      a string for the second line of the legend
GO-AWAY (T)  T or NIL determines if the close box is functional 
CONTENT-ONLY T or NIL determines if only graph content is shown

IN - The IN keyword determines the plot's containing window. If IN is unused the plot is in its own independent window. If IN is NIL the plot is in the XLISPSTAT window. IF IN is T the plot is in the active container, if there is one, or in XLISPSTAT window if there is no active container. If a menu item is used to create the plot, IN is set by the menu item to direct the plot to the appropriate container."


  (let* ((numargs (length args)))
    (cond
      ((not data)                               ; 0 args: new style
       (mosaic-plot-new))
      ((and data (not args))                    ; 1 arg:  new style
       (mosaic-plot-new data))
      ((and (listp data)           
            (first args)
            (listp (first args)))               ; 2 args, both lists: old style
       (apply #'mosaic-plot-classic data args))
      ((> (length args) 1)                      ; 3 or more args: new style 
       (apply #'mosaic-plot-new data args))
      (t ;error
         (fatal-message " Mosaic-Plot: Bad Argument Structure"))
      )))


(defun bar-graph (&optional (data nil data?) &rest args)
"Creates a side-by-side frequency or probability bar graph of 1- to 4-way data, or stacked bar graph for 2- or 3-way data.

BAR-GRAPH accepts two types of data: CELL DATA (data organized as table cells) and VARIABLE DATA (data organized as variables). The type of data is determined from the nature of the arguments: If there are at least two arguments, and the first two are each a list, the data are CELL data. Otherwise, they are VARIABLE DATA.

Arguments for CELL data:
REQUIRED:     CELLS   list of cells in way-major order. 
              LEVELS  list giving the number of levels for each way. 
KEYWORDS:     (see below)

Arguments for VARIABLE data:
OPTIONAL:     DATA    identifies the data (see below).
KEYWORDS:     (see below)

DATA - The optional DATA argument may be omitted or NIL, or may be a data object, a list of numeric or string elements, a list of variable objects, a list of equal-length lists, a vector, a list of equal-length vectors, or a matrix. If not specified or NIL, DATA is assumed to be $, the current dataobject. In all cases DATA is converted into a list of equal-length vectors, one vector for each CATEGORY variable in $, the current-data. The plot is constructed from the first vector in the list of vectors.

Keyword arguments for both types of data:
KEYWORD:     WAY-LABELS, LEVEL-LABELS, FREQ, STACKED, 
             COLOR-VALUES, (STANDARDIZE T), (CONNECT T) 
             IN, (SHOW T), LOCATION, SIZE, TITLE, MENU,  
             LEGEND1, LEGEND2, TOP-MOST, GO-AWAY, CONTENT-ONLY

Keyword arguments which are unique to BARGRAPH:
WAY-LABELS   A list specifying the names of the ways.
LEVEL-LABELS A list of lists, one sublist for each way of the data.
             The lists are in the same order as the way-labels.
             Each sublist specifies the names of the levels of a way.
FREQ         Indicates whether the data are frequency data. 
STACKED      Indicates whether intial plot is stacked (when possible)
             or side-by-side bar graph.
COLOR-VALUES A list, in way-major order, used to color cells according 
             to the specified values (standardized when STANDARDIZE T).
             By default, ViSta generates the color values.
STANDARDIZE  T or NIL determines if the color-values are standardized.
CONNECT      Indicates whether bars are connected by rows.

Keyword arguments shared with other plots:
IN (unused)  T, NIL, (UNUSED) or CONTAINER (see below)
SHOW (T)     T or NIL determines if the plot is shown when created
TOP-MOST (T) T or NIL determines whether plots are always on top
LOCATION     a list (x y) locating the plot's upper-left corner 
SIZE         a list (w h) of the plot's width & height 
MENU         T or NIL to install the graph's menu on the menubar
TITLE        a  string shown in the graph window title bar 
LEGEND1      a string for the first line of the legend 
LEGEND2      a string for the second line of the legend
GO-AWAY (T)  T or NIL determines if the close box is functional 
CONTENT-ONLY T or NIL determines if only graph content is shown

IN - The IN keyword determines the plot's containing window. If IN is unused the plot is in its own independent window. If IN is NIL the plot is in the XLISPSTAT window. IF IN is T the plot is in the active container, if there is one, or in XLISPSTAT window if there is no active container. If a menu item is used to create the plot, IN is set by the menu item to direct the plot to the appropriate container."


  (let* ((numargs (length args)))
    (cond
      ((not data)                               ; 0 args: new style
       (bar-graph-new))
      ((and data (not args))                    ; 1 arg:  new style
       (bar-graph-new data))
      ((and (listp data)
            (first args)
            (listp (first args)))               ; 2 args, both lists: old style
       (apply #'bar-graph-classic data args))
      ((> (length args) 1)                      ; 3 or more args: new style
       (apply #'bar-graph-new data args))
      (t ;error
         (fatal-message " Bar-Graph: Bad Argument Structure"))
      )))


(defun mosaic-plot-new
  (&optional data 
       &rest args 
       &key  (ok-var-types '(category)) 
             (title "Mosaic Plot") 
             ;do not use :in?, :in??, or :in??? - reserved for system use
             (in nil in??) 
             (in? nil in???) 
             (show t) 
             freq
             gaps
             way-labels 
             level-labels 
             variable-labels ;alias of way-labels
             point-labels    ;irrelevant
             (legend1) ;(legend1 (send $ :name))
             (legend2 "Mosaic Plot") (legend (send $ :name))
             location 
             (size '(320 320)) 
             (go-away t)
             (top-most t) 
             (menu t)
             ;unique keywords follow
             plot-values        ;doesn't work correctly
             color-values
             (standardize t)
             (connect-button t)
             (plot-button nil) ; leave nil until plot-values is fixed
             )
  (let* ((actcon *active-container*)
         (in? (if in??? in? in??))
         (graph-frame (graph-frame :show nil))
         (pop-out (send graph-frame :seen-in in in?))
         (container (if (equal pop-out t) graph-frame pop-out))
         (pop-out (equal pop-out t))
         (graph-data (before-new-cells-graph data))
         (graph) (cells) (levels))
    (unless way-labels    (setf way-labels (second graph-data)))
    (unless level-labels  (setf level-labels (third graph-data)))
                          (setf cells  (first  (first graph-data)))
                          (setf levels (second (first graph-data)))
    (unless legend1       (setf legend1 legend))
    (unless title         (setf title legend2))
    (setf graph
             (send mosaic-proto 
                   :new cells levels freq
                   plot-values color-values standardize 
                   connect-button plot-button gaps
                   way-labels level-labels legend1 legend2 
                   title nil size location 
                   ))
    (when graph
          (send graph :after-new-plot pop-out top-most show size container))
    graph))
  

(defun bar-graph-new
  (&optional data 
       &rest args 
       &key  (ok-var-types '(category)) 
             (title) 
             ;do not use :in?, :in??, or :in??? - reserved for system use
             (in nil in??) 
             (in? nil in???) 
             (show t) 
             freq freqs

             way-labels 
             level-labels 
             variable-labels ;alias of way-labels
             point-labels    ;irrelevant
             (legend1) 
             (legend2) (legend (send $ :name)) ;alias of legend1
             location 
             (size '(320 320)) 
             (go-away t) 
             (top-most t) 
             (menu t)
             ;unique keywords follow
             
             color-values
             (standardize t)
             (connect t) 
             (stacked nil)
             )

  (let* ((actcon *active-container*)
         (in? (if in??? in? in??))
         (graph-frame (graph-frame :show nil))
         (pop-out (send graph-frame :seen-in in in?))
         (container (if (equal pop-out t) graph-frame pop-out))
         (graph-data (before-new-cells-graph data));(before-new-bargraph data)
         (graph) (cells) (levels))
    (unless way-labels    (setf way-labels (second graph-data)))
    (unless level-labels  (setf level-labels (third graph-data)))
                          (setf cells  (first  (first graph-data)))
                          (setf levels (second (first graph-data)))
    (when (= 1 (length way-labels)) (setf stacked nil))
    (unless legend1       (setf legend1 legend))
    (unless legend2       (setf legend2 (if stacked "Stacked Bar Graph" "Bar Graph")))
    (unless title         (setf title legend2))
    (if (or freq freqs)   (setf freq t))
 
    (when in? (enable-container container));fwy dec 2002

    (setf graph
          (send stacked-bar-graph-proto 
                :new cells levels 
                :freq freq 
                :connect connect
                :way-labels way-labels 
                :level-labels level-labels
                :color-values color-values 
                :standardize standardize 
                :stacked stacked 
                :legend1 legend1 
                :legend2 legend2
                :title title 
                :show nil
                :size size 
                :location location))
    (send graph :plot-buttons :new-x nil :new-y t :free nil :mouse-mode nil)
    (when graph (send graph :after-new-plot pop-out top-most show size container))
    graph))

(defun mosaic-plot-classic 
  (cells levels 
         &key freq plot-values color-values (standardize t) 
         connect-button gaps 
         way-labels level-labels
         (legend1 (send current-object :name)) (legend2 "Mosaic Plot")
         (title "Mosaic Plot")  (show t) ;(in nil in?);fwy added in dec 2002
         (size '(250 250)) (location '(50 50)) )
"Args: CELLS LEVELS &KEY FREQ PLOT-VALUES COLOR-VALUES (STANDARDIZE T) CONNECT-BUTTON PLOT-BUTTON GAPS WAY-LABELS LEVEL-LABELS POINT-LABELS LEGEND1 LEGEND2 TITLE (SHOW T) SIZE LOCATION (IN NIL IN?)
Creates a mosaic plot of N-way table data. 
Restrictions: 6-way data; 100 cells. 
CELLS is a list of cells in way-major order. 
LEVELS specifies number of levels for each way. 
FREQ specifies that the data are frequency data. 
COLOR-VALUES is a list in same order as CELLS, which is used to color cells according to the specified values (which are standardized unless STANDARDIZE is NIL). 
PLOT-VALUES is a list of lists of values, the lists in same order as CELLS. Each list is used to make plots within cells. A button is placed on the tool bar giving the user the choice of random, dot, quantile and normal probability plots. (doesn't work correctly)
CONNECT-BUTTON specifies that the connect button is to appear on the tool bar, giving the user the choice to connect by rows or columns or both.
GAPS is a list of nway values which specify spacing between tiles (default is 5 for each way)."
  #-msdos(warning-message "Mosaic Plots do not draw correctly for this preview release of ViSta 6 for the Mac (they work in ViSta for Windows.)")

; (let* ((actcon *active-container*));fwy dec 2002
 ;   (when in? (enable-container in));fwy dec 2002
  (send mosaic-proto :new cells levels freq 
        plot-values color-values standardize 
        connect-button (if plot-values t nil) gaps
        way-labels level-labels legend1 legend2 
        title show size location 
      ;;in in?
        )
 ;   (when in? (enable-container actcon)));fwy dec 2002
  )



(defun bar-graph-classic 
  (cells levels &key (standardize t) (stacked t) color-values
         way-labels level-labels freq freqs (connect t)
         (legend (send current-object :name))
         (title "Bar Graph") (show t) ; (in nil in?);fwy added in dec 2002
         (size '(250 250)) (location '(50 50)) )
"Creates a side-by-side frequency or probability bar graph of 1- to 4-way data, or stacked bar graph for 2- or 3-way data using the Young-Kwan mosaic algorithm.
Args: CELLS LEVELS &KEY FREQ STACKED COLOR-VALUES (STANDARDIZE T) (CONNECT T) WAY-LABELS LEVEL-LABELS LEGEND TITLE (SHOW T) SIZE LOCATION (IN NIL IN?)
Arguments used as with MOSAIC PLOT.
CELLS is a list of cells in way-major order. 
LEVELS specifies number of levels for each way. 
FREQ specifies that the data are frequency data. 
STACKED specifies whether intial plot is stacked (when possible) or side-by-side.
COLOR-VALUES is a list in same order as CELLS, which is used to color cells according to the specified values (standardized when STANDARDIZE T).
CONNECT specifies whether bars are connected by rows."
  (if (or freq freqs) (setf freq t)) 
  #-msdos(warning-message "BarGraphs do not draw correctly for this preview release of ViSta 6 for the Mac (they work in ViSta for Windows.)")

  ;(let* ((actcon *active-container*));fwy dec 2002
   ; (when in? (enable-container in));fwy dec 2002
    (send stacked-bar-graph-proto 
          :new cells levels :freq freq :connect connect
          :way-labels way-labels :level-labels level-labels
          :color-values color-values :standardize standardize 
          :stacked stacked :legend1 legend 
          :legend2 (if stacked "Stacked Bar Graph" "Bar Graph") 
          :title title :show show :size size :location location
        ;  :in in :in? in?  ;fwy dec 2002
          )
   ; (when in? (enable-container actcon)));fwy dec 2002
  )



(defun before-new-cells-graph (data)
"Args: DATA
For both bargraph and mosaic plots, this function converts variable syntax to the original cell-and-level syntax"
  (let* ((catmat) (result) (cells) (numlevels)
         )
    (cond
      ((or (not data) (objectp data))
       (when (not data) (setf data $))
       (setf catmat (send $ :active-data-matrix '(category)))
       (when (> (array-dimension catmat 1) 4)
             (setf catmat 
                   (select (send $ :active-data-matrix '(category))
                           (iseq (array-dimension catmat 0)) (iseq 4))))
       (setf result (make-array-cv catmat))
       (make-cells-numlevels-waylabels-levellabels result data)
       )
      ((and (listp data) (symbolp (first data)))
       (let* ((data (if (> (length data) 4) (select data (iseq 4)) data))
              (way-labels 
               (mapcar #'(lambda (symbol) 
                           (string-capitalize (format nil "~a" symbol)))
                       data))
              (values-list
               (mapcar #'(lambda (symbol)
                           (eval symbol))
                       data))
              (catmat (transpose
                       (matrix (list (length values-list) (length (first values-list)))
                               (combine values-list))))
              (result (make-array-cv catmat)))
         (list (list (combine (first result))
                     (mapcar #'length (second result)))
               way-labels
               (second result)))
       )
      ((and (listp data) (or (vectorp (first data)) 
                             (listp (first data))))
       (cond 
         ((or (= (length data) 1) ;one list means univariate category data
              (= (length (first data)) (length (second data))));multivariate
          (when (> (length data) 4)
                (setf data (select data (iseq 4))))
          (setf catmat (apply #'bind-columns data))
          (setf result (make-array-cv catmat))
          (make-cells-numlevels-waylabels-levellabels result))))
      ((and (arrayp (first data)) (listp (second data)))
       (make-cells-numlevels-waylabels-levellabels data))
      (t (error "; incorrect data structure")))
    ))

(defun make-cells-numlevels-waylabels-levellabels (result &optional dataobj)
  (let* ((cells (combine (first result)))
         (level-labels (second result))
         (way-labels (if dataobj (send dataobj :active-variables '(category)) 
                         (mapcar #'(lambda (i) (format nil "Way~a" i))
                                 (iseq (length level-labels)))))
         (numlevels (mapcar #'length (second result))))
    (when (and way-labels
               (> (length way-labels) 4))
          (setf way-labels (select way-labels (iseq 4))))
    (list (list cells numlevels) way-labels level-labels)))




(defun stacked-bar-graph (&optional (data nil data?) &rest args)
  (if data?
      (apply #'bar-graph data (combine args :stacked t))
      (bar-graph $ :stacked t)))
